﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;

namespace ServerLibrary
{
    public class Server
    {
        readonly BackgroundWorker _listenWorker = new BackgroundWorker();
        string _socketPolicyFileContents;

        public Server()
        {
            Logger.Instance.CreateLogSource();
            _listenWorker.DoWork += ListenWorkerDoWork;
            _listenWorker.WorkerSupportsCancellation = true;
        }

        public void Start()
        {
            Logger.Instance.WriteToLog(EventLogEntryType.Information, "Starting server");
            if (_listenWorker.IsBusy)
            {
                Logger.Instance.WriteToLog(EventLogEntryType.Information, "Server is already running");

                return;
            }

            try
            {
                var location = Assembly.GetExecutingAssembly().Location;
                location = location.Substring(0, location.LastIndexOf("\\") + 1);
                using (var stream = new FileStream(location + "SocketPolicyFile.xml", FileMode.Open))
                using (var reader = new StreamReader(stream))
                {
                    _socketPolicyFileContents = string.Format("{0}\0", reader.ReadToEnd());

                }
                _listenWorker.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                Logger.Instance.WriteToLog(EventLogEntryType.Error, string.Format("An error has occured while starting the server:{0}{1}", Environment.NewLine, ex));

            }


        }

        void ListenWorkerDoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                var tcpListener = new TcpListener(IPAddress.Any, 843);
                tcpListener.Start();
                var worker = sender as BackgroundWorker;

                if (worker != null)
                    while (!worker.CancellationPending)
                    {
                        var client = tcpListener.AcceptTcpClient();

                        var clientThread = new Thread(HandleClientComm) { IsBackground = true };
                        clientThread.Start(client);
                    }
            }
            catch (Exception ex)
            {
                Logger.Instance.WriteToLog(EventLogEntryType.Error, string.Format("An error has occured while listening on port 843:{0}{1}", Environment.NewLine, ex));

            }
        }

        private void HandleClientComm(object client)
        {
            try
            {
                var tcpClient = (TcpClient)client;
                var clientStream = tcpClient.GetStream();

                var message = new byte[4096];

                while (true)
                {
                    int bytesRead;

                    try
                    {
                        bytesRead = clientStream.Read(message, 0, 4096);
                    }
                    catch
                    {
                        break;
                    }

                    if (bytesRead == 0)
                    {
                        break;
                    }

                    var encoder = new ASCIIEncoding();
                    var request = encoder.GetString(message, 0, bytesRead);


                    if (request != "<policy-file-request/>\0")
                    {
                        Logger.Instance.WriteToLog(EventLogEntryType.Warning, "Invalid communication received from client " + tcpClient.Client.RemoteEndPoint);
                        break;
                    }
                    var reply = encoder.GetBytes(_socketPolicyFileContents);
                    clientStream.Write(reply, 0, reply.Count());
                    clientStream.Flush();
                    break;

                }

                tcpClient.Close();
            }
            catch (Exception ex)
            {
                Logger.Instance.WriteToLog(EventLogEntryType.Error, string.Format("An error has occured while handling client communication:{0}{1}", Environment.NewLine, ex));

            }
        }


        public void Stop()
        {
            Logger.Instance.WriteToLog(EventLogEntryType.Information, "Stopping server");

            if (_listenWorker.IsBusy)
                _listenWorker.CancelAsync();
        }
    }
}
